home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-06-18 | 24.0 KB | 890 lines | [TEXT/MPS ] |
- ; The Essence-Shell Hack
-
- ; To Do:
- ; _ use a resource or table to specify which traps and vectors to patch,
- ; and have a small routine to do all the patching.
-
- ; Allan and Scott wrote this one day in June, not long before MacHack ’92
-
- ; arf 6/16/92 Fixed up the menuHook stuff. Patching InitMenus was bogus
- ; because we were only storing one old MenuHook value, but each
- ; app gets its own copy, and we’d have to maintain one per
- ; process. That would be lame. Now we’ll hook in right
- ; as the user clicks in the menu bar, then unhook when they’re done.
- ; stb 6/16/92 Showed this to a bunch of guys who had next to nothing
- ; to say. Gee, thanks, guys :-) Normalized spelling,
- ; and added more comments.
- ; stb 6/16/92 Whoops, InitMenus clears MenuHook. Time to tail-patch InitMenus!
- ; stb 6/16/92 Hook into MenuHook.
- ; stb 6/16/92 Merge in Allan’s Gestalt code. It’s hard to get used
- ; to this three hour time difference!
- ; stb 6/15/92 Add alternate icon drawing; try drawing all the way
- ; across the menu bar instead of a simple rect at the left.
- ; Hmm, it fits better, but it’s harder to see it all at once.
- ; stb 6/14/92 Change some names for clarity
-
- ;Include only the minimum necessary!
-
- CASE OBJECT
- STRING ASIS
-
- PRINT PUSH
- PRINT OFF
-
- INCLUDE 'Traps.a'
- wholeQuick EQU 1
- INCLUDE 'QuickEqu.a'
- wholeSystem EQU 1
- INCLUDE 'SysEqu.a'
- ;wholeTools EQU 0
- ; INCLUDE 'ToolEqu.a'
- ; INCLUDE 'PackMacs.a'
- ; INCLUDE 'Types.a'
-
- PRINT POP
-
- SEG 'Essential'
- PROC
- StartOfCode
- ; _Debugger ; it’s good to make it easy to trace while developing…
- Bra Essential
- DC.B 'Allan & Scott wrote this one day shortly before MacHack ’92'
-
- Align 2
-
- WayBadValue equ $50FF8001 ; borrowed this value from EvenBetterBusError
- ; just in case we do something wrong, we’ll
- ; know right away.
-
- ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- HeapBlock ;This block contains the patches.
- MenuHook equ $A30
-
- PatchMenuSelect
- ; Stuff MenuHook with our jump table entry to our drawing proc.
- ; We do this because InitMenus clears out MenuHook.
-
- LEA MenuHook,A0 ; Strange, if I hadn’t declared MenuHook, Asm
- ; thought it should be *+99E!
- Lea OldMenuHook,A1
- move.L (A0),(A1) ; Save the old one...
- Move.L pMenuHookEA,(A0) ; stuff our proc in, and just assume, for now,
- Move.L OldMenuSelect,A0
- Clr.L -(SP) ; room for the new result
- Move.L 8(SP),-(SP) ; copy the mouse pt
- JSR (A0) ; Call the old one
- Move.L (SP)+,8(SP) ; put the result back for the caller
- Move.l (SP)+,(SP) ; Push the return address
- LEA MenuHook,A0
- Move.L oldMenuHook,(A0) ; stuff our proc in, and just assume, for now,
- ; that no one else is patching it.
- RTS
- OldMenuSelect DC.L WayBadValue
- pMenuHookEA DC.L WayBadValue ; <ea> of pMenuHook+4. Can’t get to it via
- ; other means because it’s in a separate block.
-
- PatchNewHandle
- ; Count each time through.
- Move.L A0,-(sp)
- LEA NewHandleCounter,A0
- Add.L #1,(a0)
- Move.L (SP)+,A0
- Move.L OldNewHandle,-(sp)
- RTS
- OldNewHandle DC.L WayBadValue
-
- PatchDisposeHandle
- ; Count each time through.
- Move.L A0,-(sp)
- LEA DisposeHandleCounter,A0
- Add.L #1,(a0)
- Move.L (SP)+,A0
- Move.L OldDisposeHandle,-(sp)
- RTS
- OldDisposeHandle DC.L WayBadValue
-
-
- PatchNewPtr
- ; Count each time through.
- Move.L A0,-(sp)
- LEA NewPtrCounter,A0
- Add.L #1,(a0)
- Move.L (SP)+,A0
- Move.L OldNewPtr,-(sp)
- RTS
- OldNewPtr DC.L WayBadValue
-
-
- PatchDisposePtr
- ; Count each time through.
- Move.L A0,-(sp)
- LEA DisposePtrCounter,A0
- Add.L #1,(a0)
- Move.L (SP)+,A0
- Move.L OldDisposePtr,-(sp)
- RTS
- OldDisposePtr DC.L WayBadValue
-
- PatchRead
- ; Don’t count Read’s, but instead decide whether GetResource or LoadSeg
- ; hit the disk, and count for them.
- Move.L A0,-(sp)
- LEA ReadCounter,A0
- Add.L #1,(a0)
- Move.W inLoadSeg,D0 ; can you see why this is not really giving
- ; us what we’d really like to get?
- Beq.S @1
- LEA LoadSegHitDisk,A0
- Add.L #1,(A0)
- @1 Move.W inGetResource,D0 ; this lets us see that the GetResource actually
- ; hit the disk, so it cost us something.
- Beq.S @2
- LEA GetResourceHitDisk,A0
- Add.L #1,(A0)
- @2 Move.L (SP)+,A0
- Move.L OldRead,-(sp)
- RTS
- OldRead DC.L WayBadValue
-
- PatchWrite
- ; Count each time through.
- Move.L A0,-(sp)
- LEA WriteCounter,A0
- Add.L #1,(a0)
- Move.L (SP)+,A0
- Move.L OldWrite,-(sp)
- RTS
- OldWrite DC.L WayBadValue
-
- PatchLoadSeg
- ; Count each time through.
- ; You just can’t tail-patch this trap, nor can you change any registers.
- Move.L A0,-(sp)
- LEA LoadSegCounter,A0
- Add.L #1,(a0)
- LEA inLoadSeg,A0
- Move.W #1,(A0)
- Move.L (SP)+,A0
- Move.L OldLoadSeg,-(sp)
- RTS
- OldLoadSeg DC.L WayBadValue
-
- GetResourceFrame RECORD {Link},Decr
- Result DS.L 1 ; Stack frome for GetResource
- Type DS.L 1
- ID DS.W 1
- Return DS.L 1
- Link DS.L 1
- FrameSize EQU *-GetResourceFrame
- ENDR
-
- PatchGetResource
- ; Count each time through, and set a flag so we can tell if we hit the disk,
- ; and count those, too.
- With GetResourceFrame
- Link A6,#FrameSize
- Move.L A0,-(sp) ; save A0
- LEA GetResourceCounter,A0
- Add.L #1,(a0)
- LEA inGetResource,A0
- Move.W #1,(A0)
- Move.L (SP)+,A0 ; restore A0
-
- Move.L Result(a6),-(sp) ; Move the result value...
- Move.L Type(a6),-(sp) ; and the type
- Move.W ID(a6),-(sp) ; and the ID
-
- Pea MyTailPatch ; The place for us to return to
- Move.L OldGetResource,-(sp)
- RTS ; Do Scott’s Really cool Jump with No registers Blown
-
- MyTailPatch
- Move.L A0,-(SP)
-
- LEA inGetResource,A0
- Clr.W (A0) ; OK, So now we are back, and we can clean up
- LEA inLoadSeg,A0
- Clr.W (A0)
-
- Move.L (SP)+,A0
-
- Move.L (SP)+,Result(a6)
- Unlk A6
- Move.L (SP),6(SP) ; Put the return address up the stack,
- Add #6,SP ; and clean up the stack
- RTS
-
- EndWith
-
- OldGetResource
- DC.L WayBadValue
-
-
- redrawInterval equ 60
-
- PatchMenuHook
- ; for now, just drop on through. As it currently stands, this
- ; slows down menu selection a lot, but it looks cool.
- MoveM.L D0-D2/A0-A1,-(SP)
- BSR.S DoTheDrawing
- LEA OldMenuHook,A0
- Move.L OldMenuHook,D0
- BEq.S @Done ; is it NIL?
- CMP.L #-1,D0 ; is it F’s?
- @Done MoveM.L (SP)+,D0-D2/A0-A1 ; cool, this doesn’t whack the CCs.
- BEq.S @WowNobodyElseIsOnMenuHook ; jumping to 0 is usually a bad idea
- Move.L OldMenuHook,-(sp)
- @WowNobodyElseIsOnMenuHook
- RTS
-
- OldMenuHook
- DC.L WayBadValue
-
-
- PatchGNEFilter
-
- MoveM.L D0-D2/A0-A1,-(SP)
-
- Move.L evtTicks(A1),D1 ; tickCount as of now
- Move.L GNEFilterTimer,D2 ; tickCount at last update
- sub.L D2,D1 ; ticks since last update
- cmp.L #redrawInterval,D1
- ; blt.S @Done ; branch if elapsed < redrawInterval
- LEA GNEFilterTimer,A0
- Move.L evtTicks(a1),(a0) ; remember the time
-
- ; Clr.W -(SP)
- ; _FlashMenuBar
- ; LEA DebugFlag,A0
- ; Tst.W (A0)
- ; Bne.S @Done
- ; _Debugger
-
- BSR.S DoTheDrawing
- BSR ClearTheDataBlock
-
- LEA OldGNEFilter,A0
- Tst.L (A0)
- @Done MoveM.L (SP)+,D0-D2/A0-A1 ; cool, this doesn’t whack the CCs.
- BEq.S @WowNobodyElseIsOnGNEFilter ; jumping to 0 is usually a bad idea
- Move.L OldGNEFilter,-(sp)
- @WowNobodyElseIsOnGNEFilter
- RTS
-
- OldGNEFilter
- DC.L WayBadValue
- GNEFilterTimer
- DC.L 0
-
-
-
- DoTheDrawing
- ; save the port
- ; set the port to the WindowMgr port
- ; draw something
-
- WMgrPort equ $9DE
-
- ; save our registers
- ; d4 thePort
- ; d5 windowPtr
- MoveM.L a0-a2/d4-d5,-(sp)
-
- ; save thePort
- Movea.L (a5),a0 ; get address of thePort
- Move.L (a0),d4 ; save it
- ; set thePort to the WMgrPort
- Movea.L WMgrPort,a2
- Move.L a2,-(A7) ; keep it handy
- _SetPort
-
- ; Save the clip
- Clr.L -(SP) ; save it on the stack for later
- _NewRgn
-
- Move.L (sp),-(sp) ; spare copy of the handle for SetClip
- Move.L (sp),-(sp) ; spare copy of the handle for DisposeRgn
- _GetClip ; this consumes the first copy of the
- ; handle, but the second copy points
- ; to the same thing, and we’ll leave it
- ; there for a while.
-
- ; set the clip to the whole screen
- Pea portBits+bounds(a2) ; the rectangle of the window mgr port
- _ClipRect
-
- ; OffsetRect( copy of the bitmap rect, right(thePort^.portRect), bottom(thePort^.portRect) )
- ; Set up the target rectangle to be where the grow icon is
- ; LEA pTargetRect,a1 ; point to the target rectangle
- ; Move.L a1,-(sp) ; push target rectangle address
-
- ; LEA bounds+pBitmap,a0 ; point to the rect in the bitmap
- ; Move.L (a0)+,(a1)+ ; copy first part of rect into target rectangle
- ; Move.L (a0)+,(a1)+ ; copy second part
-
- ; Move.L a2,a0 ; a0 <- thePort
- ; Move.L portRect+botRight(a0),-(sp) ; botRight(thePort)
-
- ; Move.L (sp),d0 ; offset the size of the grow icon
- ; sub.W #$0D,d0
- ; swap d0
- ; sub.W #$0E,d0
- ; swap d0
- ; Move.L d0,(sp)
- ; _OffsetRect
-
- ; this is where we draw the icon
- ; CopyBits (srcBits,dstBits: BitMap; srcRect,dstRect: Rect; mode: INTEGER; maskRgn: RgnHandle)
-
- ShiftMask equ 0
-
- LEA KeyMap,a0
- BTST #ShiftMask,7(a0)
- BEQ.S @NormalDrawing
-
- LEA pAlternateBitMap,a0
- Move.L a0,-(sp) ; push the icon
- LEA pIcon,a1
- Move.L a1,(a0)
-
- Movea.L WMgrPort,a0
- LEA portBits(a0),a0 ; push dstBits, thePort^.portBits
- Move.L a0,-(sp)
-
- LEA bounds+pAlternateBitMap,a0 ; point to the rect in the bitmap
- Move.L a0,-(sp) ; source rect is from the bitmap
- Bra.S @AbnormalDrawing
-
- @NormalDrawing
- LEA pBitmap,a0 ; push the counters as srcBits
- Move.L a0,-(sp)
-
- Movea.L WMgrPort,a0
- LEA portBits(a0),a0 ; push dstBits, thePort^.portBits
- Move.L a0,-(sp)
-
- LEA bounds+pBitmap,a0 ; point to the rect in the bitmap
- Move.L a0,-(sp) ; source rect is from the bitmap
-
- @AbnormalDrawing
- ; LEA pTargetRect,a0 ;
- Move.L a0,-(sp) ; dest rect is bottom-right of the window
-
- Move.W #srcCopy,-(sp) ; push mode = srcCopy=0
- Move.L #0,-(sp) ; push maskRgn = NIL
- _CopyBits
-
- _SetClip ; restore the clip with the rgn we saved
- ; on the stack earlier
- _DisposeRgn ; dispose the rgn. Good thing we saved
- ; a copy on the stack, huh?
- ; Made a really common mistake earlier
- ; by forgetting to make this call. Didn’t
- ; find out until I left the machine running
- ; long enough to run a heap completely out
- ; of memory.
- ; ••• maybe we should set the heap to something like SysZone so we don’t
- ; ••• screw up apps with finely-tuned heaps (like the Finder).
- ; ••• This is being way too cavalier, but we don’t have any time left! Argh!
-
- Bail
- Move.L d4,-(sp) ; put the saved thePort back the way it was
- _SetPort
-
- @done
- MoveM.L (sp)+,a0-a2/d4-d5 ; put the registers back
- quickExit
- RTS
-
- ; restore the port
- Align 2
-
-
- ; This is the routine called by Gestalt to return the Proc Pointer.
- ;
- ; OSErr gestaltSelectorProc(OSType selector,long *response);
- ;
- ; Since this is called from Gestalt, we do not have to save any registers
-
- ReturnTheGestaltHandlerProc
-
- LEA GestaltHandlerProc,A1
- Move.W #0,$0a(Sp) ; No Error occurred here!
- Move.L 4(SP),A0
- Move.L A1,(A0) ; put the result into the right place....
- Move.L (SP)+,A0 ; Get the return address
- Addq.W #8,A7 ; Lost the args
- Jmp (A0) ; And return
-
- ReturnDataBlock
- LEA NewHandleCounter,A1
- RTS
-
- ;
- ; This Function clears the counters, and updates the running totals...
- ;
-
- ClearTheDataBlock
- LEA NewHandleCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA DisposeHandleCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA NewPtrCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA DisposePtrCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA ReadCounter ,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA WriteCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA LoadSegCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA LoadSegHitDisk,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA GetResourceCounter,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- LEA GetResourceHitDisk,A0
- Move.L (A0),D0
- Add.L D0,4(A0)
- Clr.L (A0)
- Move.L #0,A1
-
- RTS
-
-
-
- ; Define a routine actually does the gestalt things....
- ; Has the following interface.
- ;
- ; Defined using Pascal syntax, since we may want to call it from there!
- ;
- ; long GestaltHandlerProc(short selector, char *param);
- ;
-
- sTablePointer equ 0
- sClearTable equ 1
- sUninstall equ 2
-
-
- GestaltHandlerFrame RECORD {Link},Decr
- Result DS.L 1 ; Stack frome for GestaltHandlerProc
- selector DS.W 1
- param DS.L 1
- Return DS.L 1
- Link DS.L 1
- FrameSize EQU *-Link
- ENDR
-
- GestaltHandlerProc
- With GestaltHandlerFrame
- Link A6,#FrameSize ; No need for locals here
- MoveM.L A0-A2/D0-D2,-(SP) ; save some registers
- Move.W selector(A6),D0
- Move.L param(A6),A1
- ASL.W #2,D0 ; multiply by 4
- LEA myJumpTable,A0
- Move.W (A0,D0.W),D0 ; index to find the right code...
- JSR (A0,D0.W) ; and do the thing....
- Move.L A1,Result(A6) ; and put the result back
- Unlk A6
- MoveM.L (SP)+,A0-A2/D0-D2 ; restore the registers
- Move.L (SP),$6(A6) ; Move the return address up....
- Addq #6,SP ; clean up the stack
- RTS
- EndWith
-
- ; Set up our jumptable.
- ; All these values should be negative, since they are before this!
- ;
-
- myJumpTable
-
- DC.W ReturnDataBlock - myJumpTable
- DC.W ClearTheDataBlock - myJumpTable
- DC.W RemovePatches - myJumpTable
- DC.W 0
-
-
-
- Align 2
-
-
- ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
-
- GeneralStorage
-
- PatchPtr DC.L 0 ; to keep a ptr to the patch table
- DebugFlag DC.W 1 ; swapped this and PatchPtr to keep .W’s together. Seems neater.
- didARead DC.W 0
- inGetResource DC.W 0
- inLoadSeg DC.W 0
-
- pAlternateBitMap
- DC.L WayBadValue ; baseaddress will point to pIcon
- DC.W 80 ; rowBytes = 2
- ; rect is top,left,bottom,right
- DC.W $0,$0,1,640 ; rect = (0,0)(32 bits,10 values + 9 pad values)
- pIcon DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
- DC.L 0
-
-
- pRectangle DS.W 4 ; a rect needs four words
- pTargetRect DS.W 4
-
- pBitmap
- DC.L WayBadValue ; baseaddress will point to pIcon
- DC.W 80 ; rowBytes = 20Longs * 4bytes/Long
- ; rect is top,left,bottom,right
- DC.W $0,$0,1,640 ; rect = (0,0)(32 bits,10 values + 9 pad values)
- pBitMapBaseAddress
- ; The table is kept as two longs, The first is the count,
- ; which is reset every time, and the second is a running total, Never reset.
-
- NewHandleCounter DC.L 0,0
- DisposeHandleCounter DC.L 0,0
- NewPtrCounter DC.L 0,0
- DisposePtrCounter DC.L 0,0
- ReadCounter DC.L 0,0
- WriteCounter DC.L 0,0
- LoadSegCounter DC.L 0,0
- LoadSegHitDisk DC.L 0,0
- GetResourceCounter DC.L 0,0
- GetResourceHitDisk DC.L 0,0
-
- EndOfTheList DC.L -1,-1,-1,-1
-
-
- ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- RemovePatches
- ; This routine goes in and removes the patches installed.
- ; then disposes of itself.... REMARKABLE!!!
-
- ; First set up the real patches
-
- Move.L PatchPtr,a0
-
- Move.L OldNewHandle,A1
- Move.L a1,pNewHandle-JumpTable(A0)
-
- Move.L OldMenuSelect,A1
- Move.L a1,pMenuSelect-JumpTable(A0)
-
- Move.L OldDisposeHandle,A1
- Move.L a1,pDisposeHandle-JumpTable(A0)
-
- Move.L OldNewPtr,A1
- Move.L a1,pNewPtr-JumpTable(A0)
-
- Move.L OldDisposePtr,A1
- Move.L a1,pDisposePtr-JumpTable(A0)
-
- Move.L OldRead,A1
- Move.L a1,pRead-JumpTable(A0)
-
- Move.L OldWrite,A1
- Move.L a1,pWrite-JumpTable(A0)
-
- Move.L OldLoadSeg,A1
- Move.L a1,pLoadSeg-JumpTable(A0)
-
- Move.L OldGetResource,A1
- Move.L a1,pGetResource-JumpTable(A0)
-
- Move.L OldGNEFilter,A1
- Move.L a1,pGNEFilter-JumpTable(A0)
-
- LEA pDummyGestalt-JumpTable(A0),A1
- Move.L A1,pGestaltFunc-JumpTable(A0)
-
- LEA HeapBlock,a0
- _DisposPtr
- RTS
-
-
- HeapBlockEnd
-
- ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
-
- JumpTable
- ; This block contains the jumps so we can dispose of the real patches
- ; later if we want to.
-
- ; remember to build a MacsBug template to display this stuff with names.
-
- ; Ok, this has grown to the point where it should really be table-driven,
- ; but it’s getting close to time for the talk…
-
- DC.B 'MaChAcK'
- ALIGN 4
-
- MACRO
- OurStandardJumpTableEntry
- DC.L WayBadValue
- Move.L *-4,-(sp)
- RTS
- ENDM
-
-
- pGNEFilter OurStandardJumpTableEntry
- pMenuHook OurStandardJumpTableEntry
- pMenuSelect OurStandardJumpTableEntry
- pNewHandle OurStandardJumpTableEntry
- pDisposeHandle OurStandardJumpTableEntry
- pNewPtr OurStandardJumpTableEntry
- pDisposePtr OurStandardJumpTableEntry
- pRead OurStandardJumpTableEntry
- pWrite OurStandardJumpTableEntry
- pLoadSeg OurStandardJumpTableEntry
- pGetResource OurStandardJumpTableEntry
- pGestaltFunc OurStandardJumpTableEntry
-
- ; We define this, so that when we uninstall, we can handle a gestalt call....
- ; And just return an error
- ; This is because Gestalt does not allow us to UNINSTALL a handler....
- ; hmmm.... BOGUS!
-
- pDummyGestalt
- Move.W #-5551,$C(Sp) ; Selector Not defined!
- Move.L (SP),8(SP) ; Get the return address
- Addq.W #8,A7 ; Lose the args
- RTS ; And return
-
- JumpTableEnd
- ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
-
- Credits
- DC.B 'AppleLink addresses: Allan & Scott'
-
- ALIGN 2
-
- Essential
-
- ;Set up here.
-
- ; Typically, you should mark your INIT resource as Preload & Locked.
- ; This gets it in the "application" heap nice and early and nice and low.
- ; Because we are going to do that, we’re not going to waste code to
- ; do what the resource manager is happy to do for us.
-
- ; lea StartOfCode,a0
- ; _RecoverHandle
- ; _HLock ; just lock me down in case...
-
- ; Do the polite thing, and don’t load if the user doesn’t want us.
- LEA KeyMap,a0
- BTST #ShiftMask,7(a0)
- BNZ BailOut
-
- NewHandle equ $A122
- MenuSelect equ $A93D
- DisposeHandle equ $A023
- NewPtr equ $A11E
- DisposePtr equ $A01F
- Read equ $A002
- Write equ $A003
- LoadSeg equ $A9F0
- GetResource equ $A9A0
-
- ; jGNEFilter equ 666 ; You decide…
-
- ; Set up the patches-to-be. We get the old trap or vector address.
- ; We then stuff that address into a piece of storage right after the
- ; patch code which uses it. Note that this is making the change to
- ; the INIT resource. Down below we create the patch block and move
- ; the patch code and the embedded addresses we store here into a new
- ; block in the system heap.
-
- GetAndRememberOldTrapAddresses
-
- LEA OldGNEFilter,A0
- Move.L jGNEFilter,(A0) ; save off the old jGNEFilter
-
- MACRO
- SaveOldTrapAddress &trapNumber, &trapType, &storage
- Move.W #&trapNumber,D0
- _GetTrapAddress &trapType
- LEA &storage,A1
- Move.L A0,(A1)
- ENDM
-
- SaveOldTrapAddress MenuSelect, newTool, OldMenuSelect
- SaveOldTrapAddress NewHandle, newOS, OldNewHandle
- SaveOldTrapAddress DisposeHandle, newOS, OldDisposeHandle
- SaveOldTrapAddress NewPtr, newOS, OldNewPtr
- SaveOldTrapAddress DisposePtr, newOS, OldDisposePtr
- SaveOldTrapAddress Read, newOS, OldRead
- SaveOldTrapAddress Write, newOS, OldWrite
- SaveOldTrapAddress LoadSeg, newTool, OldLoadSeg
- SaveOldTrapAddress GetResource, newTool, OldGetResource
-
- ; Put the patch jump table into a system heap block, henceforth called JumpTable
-
- CreateJumpTableBlock
- Move.L #JumpTableEnd-JumpTable,D1
- Move.L D1,D0
- _NewPtr sys
- Move.L A0,A1 ; the new pointer block is the destination
- LEA JumpTable,A0 ; the jump table is what we’re copying
- Move.L D1,D0
- _BlockMove ; copy the jump table
- LEA PatchPtr,A0
- Move.L a1,(A0) ; remember where we left the jump table
-
- ; Put the patch code into a system heap block, henceforth called HeapBlock
-
- CreatePatchBlock
- Move.L #HeapBlockEnd-HeapBlock,D1
- Move.L D1,D0
- _NewPtr sys
- Move.L A0,A1 ; the new pointer block is the destination
- LEA HeapBlock,A0 ; HeapBlock is the source
- Move.L D1,D0 ; D1 is how many bytes are in our patch
- _BlockMove ; copy all of the patch code into the new block
- Move.L A1,A2 ; Save the new pointer block in A2
-
- InstallPatches
-
- Move.L PatchPtr,a1
-
- FlushTheCache
- _FlushInstructionCache ; just flush all the caches. We just moved code
- ; into a couple of blocks which might still have addresses
- ; in the instruction cache. Currently BlockMove does
- ; this, but why count on it when it only costs 4 bytes?
-
- ; Detailed description of how we hook in:
- ; 1. Figure out the address of the patch routine in the new block of patches.
- ; 2. Stuff the patch routine’s address into the new jump table block.
- ; 3. Figure out the address of the “Move.L *-4,-(sp)” which is right after
- ; the address we just stored in the jump table.
- ; 4. Hook that address in. Either stuff it into the right vector, or set
- ; the trap address, as appropriate.
- ;
- ; The blow-by-blow:
- ;
- ; 1. Point A0 at the patch block (at A2) plus the offset to the patch routine.
- ; A0 := A2 + (<ea> of patch routine - <ea> of the start of the patches)
- ; LEA PatchGNEFilter-HeapBlock(A2),A0
- ;
- ; 2. Stuff that address into the newly-allocated jump table (at A1) plus the offset
- ; to the jump table entry.
- ; Ptr( A1 + (<ea> of the jump table entry - <ea> of the start of the jump table) := A0
- ; Move.L A0,pGNEFilter-JumpTable(A1)
- ;
- ; 3. Point A0 at the “Move.L *-4,-(sp)”
- ; LEA 4+pGNEFilter-JumpTable(A1),A0
- ;
- ; 4. Stuff the vector.
- ; Move.L A0,jGNEFilter
- ; or
- ; Move.W #NewHandle,D0
- ; _SetTrapAddress newOS <- newOS or newTool, as appropriate.
-
- ; Define a macro which does what we just described, but hides the grungy detail.
- ; &trapNumber can be either a trap number or a vector address
- ; &trapType can be newOS, newTool, or Vector
- ; &patch is the label on your patch routine
- ; &jumpTableEntry is the label on your jump table entry
-
- MACRO
- StuffNewAddress &trapNumber, &trapType, &patch, &jumpTableEntry
- LEA &patch-HeapBlock(A2),A0
- Move.L A0,&jumpTableEntry-JumpTable(A1)
- LEA 4+&jumpTableEntry-JumpTable(A1),A0
- IF &trapType = 'newOS' THEN
- Move.W #&trapNumber,D0
- _SetTrapAddress &trapType
- ELSEIF &trapType = 'newTool' THEN
- Move.W #&trapNumber,D0
- _SetTrapAddress &trapType
- ELSEIF &trapType = 'Vector' THEN
- Move.L A0,&trapNumber
- ENDIF
- ENDM
-
- ;Vectors
- ; to get some time, patch us into jGNEFilter and MenuHook
- StuffNewAddress jGNEFilter, Vector, PatchGNEFilter, pGNEFilter ; somebody’s got to get the utility check!
- StuffNewAddress MenuHook, Vector, PatchMenuHook, pMenuHook
-
- ;Traps
- ; patch MenuSelect to give us a chance to stuff MenuHook around tracking in the menubar and menus
- StuffNewAddress MenuSelect, newTool,PatchMenuSelect, pMenuSelect
- ; patch these to count them as they are called.
- StuffNewAddress NewHandle, newOS, PatchNewHandle, pNewHandle
- StuffNewAddress DisposeHandle, newOS, PatchDisposeHandle, pDisposeHandle
- StuffNewAddress NewPtr, newOS, PatchNewPtr, pNewPtr
- StuffNewAddress DisposePtr, newOS, PatchDisposePtr, pDisposePtr
- StuffNewAddress Read, newOS, PatchRead, pRead
- StuffNewAddress Write, newOS, PatchWrite, pWrite
- StuffNewAddress LoadSeg, newTool,PatchLoadSeg, pLoadSeg
- StuffNewAddress GetResource, newTool,PatchGetResource, pGetResource
-
- RegisterGestaltHandler
- LEA ReturnTheGestaltHandlerProc-HeapBlock(A2),A0
- Move.L A0,pGestaltFunc-JumpTable(A1)
- Move.L #'Sntl',D0
- LEA 4+pGestaltFunc-JumpTable(A1),A0
- _NewGestalt ; If it fails, then something bad happened...
- ; but nothing we can do about it now
- ; JumpTable in A1
- ; HeapBlock in A2
-
- ; Fix up the bitmap base address in the patch block.
- LEA pBitMapBaseAddress-HeapBlock(A2),A0
- Move.L A0,pBitMap-HeapBlock(A2)
-
- ;Remember where the jump table entry is so that the patch on MenuSelect can load
- ;MenuHook with the jump table entry even though it’s in a separate block
- LEA 4+pMenuHook-JumpTable(A1),A0
- Move.L A0,pMenuHookEA-HeapBlock(A2)
-
-
- Bra.S loaded
-
- ;Common exit-point.
- BailOut
-
- ShowStartupIcon
-
- ; PROCEDURE ShowINIT(iconID: Integer; moveX: Integer);
- IMPORT SHOWINIT:CODE
-
- didntLoadIconID equ -4063
- patchLoadedIconID equ -4064
-
- Move.W #didntLoadIconID,-(a7) ; Shift held -- Didn’t load
- Bra.S ShowIt
-
- loaded Move.W #patchLoadedIconID,-(a7) ; OK Show the ICON and go
- ShowIt Move.W #-1,-(a7)
- BSR SHOWINIT
-
- exit RTS
-
- ; What happens to this locked block, you ask? Easy, the heap is about to
- ; get blown away, so we really don’t have to do anything to tidy up.
-
- END
-
-
- ; ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
-